package com.xiaoxin.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.xiaoxin.autoconfig.template.OssTemplate;
import com.xiaoxin.commons.utils.Constants;
import com.xiaoxin.dubbo.api.CommentApi;
import com.xiaoxin.dubbo.api.UserInfoApi;
import com.xiaoxin.dubbo.api.VideoApi;
import com.xiaoxin.dubbo.api.focusUserApi;
import com.xiaoxin.exception.BusinessException;
import com.xiaoxin.interceptor.UserHolder;
import com.xiaoxin.model.domain.UserInfo;
import com.xiaoxin.model.enums.CommentType;
import com.xiaoxin.model.mongo.Comment;
import com.xiaoxin.model.mongo.FocusUser;
import com.xiaoxin.model.mongo.Video;
import com.xiaoxin.model.vo.ErrorResult;
import com.xiaoxin.model.vo.PageResult;
import com.xiaoxin.model.vo.VideoVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Service
public class SmallVideosService {

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;

    @DubboReference
    private VideoApi videoApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @DubboReference
    private focusUserApi focusUserApi;

    @DubboReference
    private CommentApi commentApi;

    /*
     * 发布小视频
     * videoThumbnail：封面图
     * videoFile：视频文件
     * */
    public void saveVideos(MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {
        // 1、封面图上传到阿里云OSS，获取地址
        String picUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
        // 2、视频上传到fastDfs上，获取请求地址
        // 获取文件的后缀名
        String videoName = videoFile.getOriginalFilename();
        String endName = videoName.substring(videoName.lastIndexOf(".") + 1);
        System.out.println("----------------------" + endName);
        // 文件输入流，文件长度，文件后缀，元数据
        StorePath storePath = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), endName, null);
        String videoUrl = webServer.getWebServerUrl() + storePath.getFullPath();
        // 3、创建Video对象，并设置属性
        Video video = new Video();
        video.setPicUrl(picUrl);
        video.setUserId(UserHolder.getId());
        video.setVideoUrl(videoUrl);
        video.setText("测试");
        // 4、调用API完成保存
        String flag = videoApi.save(video);
        if (StringUtils.isEmpty(flag)) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    /*
     * 查询视频列表
     * */
    @Cacheable(value = "smallVideo", key = "T(com.xiaoxin.interceptor.UserHolder).getId()+'-'+#page+'-'+#pagesize")
    public PageResult queryVideoList(Integer page, Integer pagesize) {
        // 查询redis数据
        String redisKey = Constants.VIDEOS_RECOMMEND + UserHolder.getId();
        String redisValue = redisTemplate.opsForValue().get(redisKey);
        // 判断redis中数据是否存在,判断redis中数据是否满足分页条数
        List<Video> list = new ArrayList<>();
        int redisPage = 0;
        if (!StringUtils.isEmpty(redisValue)) {
            // 调用api根据pid查询动态数据
            String[] values = redisValue.split(",");
            if ((page - 1) * pagesize < values.length) {
                List<Long> collect = Arrays.stream(values).skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(e -> Long.valueOf(e))
                        .collect(Collectors.toList());
                list = videoApi.findVideoByPids(collect);
            }
            redisPage = PageUtil.totalPage(values.length, pagesize);
        }
        // 不存在分页查询数据库视频数据
        if (CollUtil.isEmpty(list)) {
            // page=传入的页码-redis查询的总页数
            list = videoApi.queryList(page - redisPage, pagesize);
        }
        // 构建返回
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(userIds, null);
        List<VideoVo> vos = new ArrayList<>();
        for (Video video : list) {
            UserInfo userInfo = infoMap.get(video.getUserId());
            if (userInfo != null) {
                VideoVo vo = VideoVo.init(userInfo, video);
                vos.add(vo);
            }
        }
        return new PageResult(page, pagesize, 0L, vos);
    }

    /*
     * 视频用户关注
     * */

    @Cacheable(value = "userFocus", key = "T(com.xiaoxin.interceptor.UserHolder).getId()+'-'+#videoId.toString()")
    public void userFocus(Long videoId) {
        FocusUser focusUser = new FocusUser();
        focusUser.setUserId(UserHolder.getId());
        focusUser.setFollowUserId(videoId);
        focusUserApi.save(focusUser);
        /*String Key = Constants.FOCUS_KEY + UserHolder.getId();
        String hashKey = Constants.FOCUS_LIKE_KEY + focusUser.getFollowUserId().toString();
        redisTemplate.opsForHash().put(Key, hashKey, "focus");*/
    }

    /*
     * 关注or取消关注
     * */
    public void focusOrUnFocus(Long videoId) {
        // 查询redis数据
        //String redisKey = Constants.FOCUS_KEY + UserHolder.getId();
        String redisValue = redisTemplate.opsForValue().get("userFocus");
        if (StringUtils.isEmpty(redisValue)) {
            userFocus(videoId);
        } else {
            userUnFocus(videoId);
        }
    }


    /*
     * 视频用户取消关注
     * */
    @CacheEvict(value = "userFocus", key = "T(com.xiaoxin.interceptor.UserHolder).getId()+'-'+#videoId.toString()")
    public void userUnFocus(Long videoId) {
        FocusUser focusUser = new FocusUser();
        focusUser.setUserId(UserHolder.getId());
        focusUser.setFollowUserId(videoId);
        focusUserApi.delete(focusUser);
      /*  String Key = Constants.FOCUS_KEY + UserHolder.getId();
        String hashKey = Constants.FOCUS_LIKE_KEY + focusUser.getFollowUserId().toString();
        redisTemplate.opsForHash().delete(Key, hashKey);*/
    }


    /*
     * 视频点赞
     * */
    @Cacheable(value = "videolike", key = "T(com.xiaoxin.interceptor.UserHolder).getId()+'-'+#videoId.toHexString()")
    public void videolike(ObjectId videoId) {
        // 查询是否已点赞
        boolean isLike = commentApi.isLike(UserHolder.getId(), videoId, CommentType.LIKE);
        if (isLike) {
            throw new BusinessException(ErrorResult.likeError());
        }
        Video video = videoApi.findByVideoId(videoId);
        Comment comment = new Comment();
        comment.setPublishId(videoId);
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getId());
        comment.setCreated(System.currentTimeMillis());
        comment.setPublishUserId(video.getUserId());
        commentApi.saveVideoLike(comment);
    }


    /*
     * 视频取消点赞
     * */
    @CacheEvict(value = "videolike", key = "T(com.xiaoxin.interceptor.UserHolder).getId()+'-'+#videoId.toHexString()")
    public void videodislike(ObjectId videoId) {
        // 查询是否已点赞
        boolean isLike = commentApi.isLike(UserHolder.getId(), videoId, CommentType.LIKE);
        if (!isLike) {
            throw new BusinessException(ErrorResult.disLikeError());
        }
        Video video = videoApi.findByVideoId(videoId);
        Comment comment = new Comment();
        comment.setPublishId(videoId);
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getId());
        comment.setCreated(System.currentTimeMillis());
        comment.setPublishUserId(video.getUserId());
        commentApi.deleteVideoLike(comment, UserHolder.getId());
    }
}